package com.example.emos.wx.config.shiro;

import com.example.emos.wx.db.pojo.TbUser;
import com.example.emos.wx.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Set;

/**
 * @ClassName : OAuth2Realm
 * @Author : 骆发茂
 * @Date: 2021/10/10 19:44
 * @Description :
 */

/**认证和授权用的OAuth2Realm
OAuth2Realm类是AuthorizingRealm的实现类,
我们要在这个实现类中定义认证和授权的方法。
因为认证与授权模块涉及到用户模块和权限模块,
现在我们还没有真正的开发业务模块,
所以我们这里先暂时定义空的认证去授权方法,
把Shiro和JwT整合起来,在后续章节我们再实现认证与授权。*/

@Component//其他类以后会用到，其他类可以用到，给spring框架管理
/*实现类中定义认证和授权的方法
* realm:领域*/
public class OAuth2Realm3_定义认证和授权方法 extends AuthorizingRealm {

    @Autowired
    private JwtUtil_根据ID生成_解密获ID_验证TOKEN jwtUtil生成解密验证TOKEN;

    @Autowired
    private UserService userService;

    /**
     * 授权(验证权限时调用)
     * Authorization
     * 每个人都可以人脸签到，封装权限列表
     */
    /**
     *
     * @param Collection
     * @return返回权限列表
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection Collection) {
        //在认证的过程中，传入三个参数
        //SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(user,accessToken,getName());
        //用户信息，token，realm的名字
        //所以在授权的时候就可以直接getPrimaryPrincipal，获得对象
        TbUser user = (TbUser)Collection.getPrimaryPrincipal();
        //根据对象获取id
        Integer userId = user.getId();
        //根据userid获取权限
        Set<String> permsSet = userService.searchUserPermissions(userId);
        //将权限返回给info
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(permsSet);
        return info;
    }

    /**
     * 认证(验证登录时调用)
     * 认证
     * authentication
     * 传递的参数param：用户信息、token令牌、realm类的名字
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //从头部获取令牌字符串
        String accessToken = (String) token.getPrincipal();//Principal：主要的
        //通过令牌获取id，通过token找id
        int userId = jwtUtil生成解密验证TOKEN.getUserId(accessToken);
        TbUser user = userService.searchById(userId);
        if(user==null){
            throw new LockedAccountException("账号已被锁定,请联系管理员");
        }
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo/*简单的身份验证信息*/(
                user, accessToken, getName()
        );

        return info;
    }

    /**
     *
     * 原本是接口类型，用来判断传入的符不符合要求
    *把令牌转换成对象，instanceof OAuth2Token*/
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof OAuth2Token4_将客户端发送的令牌TOKEN封装成对象;
    }
}